package com.feiclub.subject.domain.service.impl;

import com.alibaba.fastjson.JSON;
import com.feiclub.subject.common.entity.PageResult;
import com.feiclub.subject.common.enums.IsDeletedFlagEnum;
import com.feiclub.subject.domain.convert.SubjectInfoConverter;
import com.feiclub.subject.domain.entity.SubjectInfoBO;
import com.feiclub.subject.domain.entity.SubjectOptionBO;
import com.feiclub.subject.domain.handle.subject.SubjectTypeHandler;
import com.feiclub.subject.domain.handle.subject.SubjectTypeHandlerFactory;
import com.feiclub.subject.domain.service.SubjectInfoDomainService;
import com.feiclub.subject.infra.basic.entity.SubjectInfo;
import com.feiclub.subject.infra.basic.entity.SubjectLabel;
import com.feiclub.subject.infra.basic.entity.SubjectMapping;
import com.feiclub.subject.infra.basic.service.SubjectInfoService;
import com.feiclub.subject.infra.basic.service.SubjectLabelService;
import com.feiclub.subject.infra.basic.service.SubjectMappingService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class SubjectInfoDomainServiceImpl implements SubjectInfoDomainService {

    private final SubjectInfoService subjectInfoService;
    private final SubjectMappingService subjectMappingService;
    private final SubjectTypeHandlerFactory subjectTypeHandlerFactory;
    private final SubjectLabelService subjectLabelService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SubjectInfoBO subjectInfoBO) {
        if (log.isInfoEnabled()) {
            log.info("SubjectInfoDomainServiceImpl.add.bo:{}", JSON.toJSONString(subjectInfoBO));
        }
//        把BO转PO
        SubjectInfo subjectInfo =
                SubjectInfoConverter.INSTANCE.convertBoToInfo(subjectInfoBO);
//        新增默认未删除
        subjectInfo.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

//        插入基本信息
        subjectInfoService.insert(subjectInfo);
//        使用工厂判断题目类型  多选  单选
        SubjectTypeHandler handler =
                subjectTypeHandlerFactory.getHandler(subjectInfo.getSubjectType());

//        insert会返回id
        subjectInfoBO.setId(subjectInfo.getId());
//        工厂的之后的SubjectTypeHandler的方法  add进去
        handler.add(subjectInfoBO);

//获取到subjectInfoBO的CategoryIdList  分类id
        List<Integer> categoryIds = subjectInfoBO.getCategoryIds();

//        标签id
        List<Integer> labelIds = subjectInfoBO.getLabelIds();

//         添加一个题目 那么题目与标签对应的关系 以及题目与分类对应的关系也要创建
//         在 subject_mapping表当中
//        category_id和label_id是多对多的关系
//        因此
        List<SubjectMapping> mappingList = new LinkedList<>();
        categoryIds.forEach(categoryId -> {
            labelIds.forEach(labelId -> {
                SubjectMapping subjectMapping = new SubjectMapping();
                subjectMapping.setSubjectId(subjectInfo.getId());
                subjectMapping.setCategoryId(Long.valueOf(categoryId));
                subjectMapping.setLabelId(Long.valueOf(labelId));
                subjectMapping.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
                mappingList.add(subjectMapping);
            });
        });
        subjectMappingService.batchInsert(mappingList);
    }
    /**
     * 分页查询
     */
    @Override
    public PageResult<SubjectInfoBO> getSubjectPage(SubjectInfoBO subjectInfoBO) {

        PageResult<SubjectInfoBO> pageResult = new PageResult<>();
//        需要向前端返回pageNo 和  pageSize   并且返回的类型定义好是PageResult
        pageResult.setPageNo(subjectInfoBO.getPageNo());
        pageResult.setPageSize(subjectInfoBO.getPageSize());
//        当前页码的起始题目序号
//          举个例子，如果 pageNo 是3，pageSize 是10，那么：
//        //start 的计算：(3−1)×10+1=21    20
        int start = (subjectInfoBO.getPageNo() - 1) * subjectInfoBO.getPageSize();
//        转换成 PO 调用infra数据交互层
        SubjectInfo subjectInfo =
                SubjectInfoConverter.INSTANCE.convertBoToInfo(subjectInfoBO);
//        统计总数   根据条件查询  根据传过来的分类  标签    以及一些题目的基本信息查询
        int count =
                subjectInfoService.countByCondition(subjectInfo, subjectInfoBO.getCategoryId()
                , subjectInfoBO.getLabelId());
        if (count == 0) {
//            表示 该类型题目没有  直接返回
            return pageResult;
        }
//        有数据则 根据 标签 分类  题目信息如难度 题目类型如多选单选  和 起始题目序号  以及每页数据  来分页查询  查询info表  和mapping表
        List<SubjectInfo> subjectInfoList =
                subjectInfoService.queryPage(subjectInfo, subjectInfoBO.getCategoryId()
                , subjectInfoBO.getLabelId(), start, subjectInfoBO.getPageSize());
//        查询到之后返回给domain层BO对象数据  因此转换
        List<SubjectInfoBO> subjectInfoBOS =
                SubjectInfoConverter.INSTANCE.convertListInfoToBO(subjectInfoList);
//        对每一个subjectInfoBOS
        subjectInfoBOS.forEach(info -> {
//            映射表实体类
            SubjectMapping subjectMapping = new SubjectMapping();
//            题目id
            subjectMapping.setSubjectId(info.getId());
//           根据查询出来的labelId查询映射表里labelId 并且去重  查询mapping表  返回的对象都只有LabelId
            List<SubjectMapping> mappingList =
                    subjectMappingService.queryLabelId(subjectMapping);
//对象装换成List<Long> labelId
            List<Long> labelIds =
                    mappingList.stream().map(SubjectMapping::getLabelId).collect(Collectors.toList());
//            根据标签id查询label表 返回Subject_Label对象  里面有id label_name等等
            List<SubjectLabel> labelList =
                    subjectLabelService.batchQueryById(labelIds);
//            把Label_Name名字收成一个List
            List<String> labelNames =
                    labelList.stream().map(SubjectLabel::getLabelName).collect(Collectors.toList());
//            这时List<SubjectInfo> subjectInfoList 里的每一个SubjectInfo都有他对应的标签名字数据
            info.setLabelName(labelNames);
        });
//
        pageResult.setRecords(subjectInfoBOS);
        pageResult.setTotal(count);
        return pageResult;
    }

    /**
     * 查询题目信息
     */
    @Override
    public SubjectInfoBO querySubjectInfo(SubjectInfoBO subjectInfoBO) {
//        查询题目信息  要查询Info表   但是  info表没有 DTO(前端需要返回的内容饿定义对象)的两个属性
//        因此在定义一个OptionBO 根据题目类型查询对应的表之后再一起返回所需要的题目答案和答案选项
        SubjectInfo subjectInfo =
                subjectInfoService.queryById(subjectInfoBO.getId());
//        根据类型查询对应的表之后调用query方法
        SubjectTypeHandler handler =
                subjectTypeHandlerFactory.getHandler(subjectInfo.getSubjectType());
//        调用query方法
//
        SubjectOptionBO optionBO =
                handler.query(subjectInfo.getId().intValue());
//        因为subjectInfoBo包含了subjectInfo和SubjectOptionBO
        SubjectInfoBO bo =
                SubjectInfoConverter.INSTANCE.convertOptionAndInfoToBo(optionBO, subjectInfo);
//        subejct_infoBo和subject_infoDto 属性暂时一样

//        根据映射表查询 对应的映射关系  查询出改题目对应的标签id
        SubjectMapping subjectMapping = new SubjectMapping();
        subjectMapping.setSubjectId(subjectInfo.getId());
        subjectMapping.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        List<SubjectMapping> mappingList =
                subjectMappingService.queryLabelId(subjectMapping);
//        stream成labelId的List
        List<Long> labelIdList =
                mappingList.stream().map(SubjectMapping::getLabelId).collect(Collectors.toList());
//        再根据对应的Label的ID List批量查询对应的LabelName
        List<SubjectLabel> labelList = subjectLabelService.batchQueryById(labelIdList);
        List<String> labelNameList = labelList.stream().map(SubjectLabel::getLabelName).collect(Collectors.toList());
        bo.setLabelName(labelNameList);
//        返回
        return bo;
    }
}